package com.ossean;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import com.ossean.dao.DBSource;
import com.ossean.dao.GatherDao;
import com.ossean.model.GatherProjectsModel;
import com.ossean.util.EDDHandler;
import com.ossean.util.FileReader;
import com.ossean.util.RegexHandler;
import com.ossean.util.StringHandler;
import com.ossean.util.StringHandler_ProjectName;

@Component("insertSynonyms")
public class InsertSynonyms extends Thread{
	
	Logger logger = Logger.getLogger(this.getClass());
	@Resource
	private DBSource dbSource;
	@Resource
	private GatherDao gatherDao;
	
	private static String gatherProjectsTableName = TableName.gatherProjectsTableName;
	private static String synonymsTableName = TableName.synonymsTableName;
	private static String pointerTableName = TableName.pointerTableName;
	private static int batchSize = 1000;
	
	@Override
	public void run(){
		long start_all = System.currentTimeMillis();
		
		while(true){
			/*
			 * update_mark:0  原始Gather_projects数据
			 * update_mark：1取完别名
			 * update_mark：2去完重
			 * 若是更新完的数据则更新update_mark字段为0
			 */
			logger.warn("==============start insert synonyms============");
			List<GatherProjectsModel> gpmList = gatherDao.selectGPMListNew(gatherProjectsTableName,0,batchSize);
			if(gpmList.size() == 0){
				try {
					logger.warn("insert synonyms:deal all projects FINALLY cost: "+(float)(System.currentTimeMillis() - start_all)/60000+" minutes");
					logger.info("all gather project have get synonyms. Sleep 5 mins");
					Thread.sleep(1000*300);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			long start = System.currentTimeMillis();
			for(GatherProjectsModel model:gpmList){
				List<String> synonymsList = getSynonyms(model);
				for(String name:synonymsList){
					dbSource.insertSynonymsNew(synonymsTableName,model.getId(),name,1);
				}
				//更新update_mark=1
				gatherDao.updateMark(gatherProjectsTableName,1, model.getId());
			}
			long end = System.currentTimeMillis();
			logger.warn("insert synonyms:deal with "+gpmList.size()+" projects cost: "+(float)(end - start)/60000+" minutes");
		}
	}
	
//	public static void main(String[] args){
//		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/applicationContext*.xml");
//		InsertSynonyms Main = applicationContext.getBean(InsertSynonyms.class);
//		
//		Main.start();
//		
//	}
	
	public List<String> getSynonyms(GatherProjectsModel model){
			
		model.setName(model.getName().trim());
		model.setDescription(model.getDescription().trim());
		
		List<String> synonymsList = new ArrayList<String>();//最终返回的同义词列表
		String description = model.getDescription();
		String prjName = model.getName();
		List<String> result = null;
		
		if(description == null)
			return result;
		List<String> linkNameList = new ArrayList<String>();//用于存储所有提取出来的关联项目名
		List<String> keywords = FileReader.read("./files/language.txt");
		
		//提取项目名括号中的信息，不是项目类型
		String bracket = StringHandler_ProjectName.getBracket(prjName);
		if(bracket != null &&!"".equals(bracket)){
			bracket = RegexHandler.extractEngDecChiAndDot(bracket);//去除括号中信息的特殊符号
			if(!RegexHandler.onlySpecialChar(bracket)){
				if(!keywords.contains(bracket.toLowerCase())){//括号中的信息不是语言类关键字词
					linkNameList.add(bracket);
					}
			}
		}
		
		//对项目名进行处理,去除公司名或基金组织的信息&&去除括号（没有公司没有括号则包含自己）
		String projectNameWithoutComName = StringHandler_ProjectName.getProjectWithoutComName(prjName);
		projectNameWithoutComName = StringHandler_ProjectName.removeBracket(projectNameWithoutComName);
		if(!"".equals(projectNameWithoutComName)){
			synonymsList.add(projectNameWithoutComName);
			logger.info("gets synonyms:" + projectNameWithoutComName + " Without ComName and remove racket");
		}
		
		
		if(description != null){
			
			List<String> beWords = FileReader.read("./files/beVerb.txt");//读取be动词表
			description = StringHandler.getFirstSentence(description);
				
			for(String beWord:beWords){
				
				String linkName = StringHandler.findLinkName(description, beWord);//按系动词表优先级进行匹配
				if(linkName == null){//表示没有匹配到当前的系动词 进行下一个匹配
					continue;
				}
				//特征短语去噪
				List<String> linkNameResult = EDDHandler.getMainAndViceDescriptionByBracket(linkName);//提取主副描述信息(括号中)
				linkNameResult = EDDHandler.getMainAndViceDescriptionByKnowAs(linkNameResult);//提取主副描述信息(known as+连词)
				linkNameResult = EDDHandler.removeComma(linkNameResult);//去除定语描述信息(逗号定语)
				linkNameResult = EDDHandler.removeDemonstrativeWords(linkNameResult);//去除定语描述信息(定冠词The)
				linkNameResult = EDDHandler.removeArrtibutiveClause(linkNameResult);//去除从句描述信息
				linkNameResult = EDDHandler.removePronoun(linkNameResult);//去除指示代词
				linkNameResult = EDDHandler.removeProject(linkNameResult);//去除项目常用词
				linkNameResult = EDDHandler.removePPCombine(linkNameResult);//去除指示代词和项目常用词两者的笛卡尔积
				linkNameResult = RegexHandler.extractEngDecChiAndDot(linkNameResult);//提取项目中
				linkNameResult = RegexHandler.removeOnlySpecial(linkNameResult);//删除只有特殊字符的同义词
				for(String name:linkNameResult){
					logger.info("be 动词之前的有： "+name);
					//be动词前不包括项目类型，且和项目名不相同
				    if(!keywords.contains(name.toLowerCase().trim()) && !name.toLowerCase().trim().equals(prjName.toLowerCase().trim()) 
				    		&& !name.toLowerCase().trim().equals(projectNameWithoutComName.toLowerCase().trim())){
				    	if(prjName.toLowerCase().indexOf(name.toLowerCase()) != -1){
				    		synonymsList.add(name);
				    		logger.info("gets synonyms:" + name + " from description before be verb");
				    	}
				    	else
				    		linkNameList.add(name);
				    }
				    	
				}
			}
		}
		
		//result包含去掉公司信息、括号内的、be动词之前的
		result = removeDupStr(linkNameList);
		logger.info("result去掉公司信息、括号内的、be动词之前的;");
		for (int i = 0;i<result.size();i++)
			System.out.println("result: "+result.get(i));
		
		String fullName = StringHandler.getFullName(projectNameWithoutComName.toLowerCase(), result);
		if(!fullName.equals("")){
			synonymsList.add(fullName.toLowerCase());//表示项目名确实是缩写 并提取到了项目全名
			logger.info("项目的全称为： "+fullName);
		}
		
		
		String shortName = StringHandler.getShortName(projectNameWithoutComName.toLowerCase(), result);
		if(!shortName.equals("")){
			synonymsList.add(shortName.toLowerCase());//表示项目名确实是全称 并提取到了项目缩写
			logger.info("项目的简称为： "+shortName);
		}
		
		//同义词要和项目名称有一定的相似度
		for(int i = 0; i < result.size(); i++){
			String extract = "";
			String synonym = result.get(i);
			String[] words = synonym.split(" ");//按照空格进行分词
			for(String word:words){
				if(model.getName().toLowerCase().indexOf(word.toLowerCase()) >= 0){//查看每个词在项目名中是否出现
					extract += word + " ";
				}
			}
			if(extract.length() !=0)
				extract = extract.substring(0, extract.length() - 1);
			//logger.info("extract : "+extract);
			if(!"".equals(extract) && !keywords.contains(extract)){
				//提取的别名不和项目名重复
				if(!extract.toLowerCase().equals(prjName.toLowerCase().trim()) && !extract.toLowerCase().trim().equals(projectNameWithoutComName.toLowerCase().trim())){
					double similarDegree = SimilarDegree(extract,projectNameWithoutComName);
System.out.println("字符串间的相似度为: "+similarDegree);
					if(similarDegree >= 0.4 && similarDegree <1.0){
						logger.info("from extract after similar： "+extract);
						synonymsList.add(extract);
					}
				}
			}
		}
		removeDupStr(synonymsList);//去除同名列表中重复的
		for(String s : synonymsList){
			logger.info("finally  synonyms:" + s + " by description");
		}
		return  synonymsList;
		}
	
	
	
	 public List<String>  removeDupStr(List<String> array){
	        List<String> list = new ArrayList<String>();
	        Set<String> set = new HashSet<String>();
	        for(String s : array){
	            if(set.add(s.toLowerCase())){
	                list.add(s);
	            }
	        }
	        return list;
	    }
	 public static double SimilarDegree(String strA, String strB){  
		  
	        String newStrA = removeSign(strA);  
	        String newStrB = removeSign(strB);  
	        int temp = Math.max(newStrA.length(), newStrB.length());  
	        int temp2 = longestCommonSubstring(newStrA, newStrB).length();  
	        return temp2 * 1.0 / temp;  
	  
	    }
	 private static String removeSign(String str) {  
	        StringBuffer sb = new StringBuffer();  
	        for (char item : str.toCharArray())  
	            if (charReg(item)){  
	                sb.append(item);  
	            }  
	        return sb.toString();  
	  
	    }  
	  
	  
	    private static boolean charReg(char charValue) {  
	  
	        return (charValue >= 0x4E00 && charValue <= 0X9FA5)  
	                || (charValue >= 'a' && charValue <= 'z')  
	                || (charValue >= 'A' && charValue <= 'Z')  
	                || (charValue >= '0' && charValue <= '9');  
	  
	    }  
	  
	    private static String longestCommonSubstring(String strA, String strB) {  
	        char[] chars_strA = strA.toCharArray();  
	        char[] chars_strB = strB.toCharArray();  
	        int m = chars_strA.length;  
	        int n = chars_strB.length;  
	        int[][] matrix = new int[m + 1][n + 1];  
	        for (int i = 1; i <= m; i++) {  
	  
	            for (int j = 1; j <= n; j++) {  
	                if (chars_strA[i - 1] == chars_strB[j - 1])  
	                    matrix[i][j] = matrix[i - 1][j - 1] + 1;  
	                else  
	                    matrix[i][j] = Math.max(matrix[i][j - 1], matrix[i - 1][j]);  
	            }  
	  
	        }  
	  
	        char[] result = new char[matrix[m][n]];  
	        int currentIndex = result.length - 1;  
	        while (matrix[m][n] != 0) {  
	            if (matrix[m][n] == matrix[m][n - 1])  
	                n--;  
	            else if (matrix[m][n] == matrix[m - 1][n])   
	                m--;  
	            else {  
	                result[currentIndex] = chars_strA[m - 1];  
	                currentIndex--;  
	                n--;  
	                m--;  
	            }  
	        }  
	        return new String(result);  
	  
	    }

		
	}

